require 'socket'
require 'zdc.doc'

module(..., package.seeall)

local Accept= {}
local Accept_mt = {__metatable = {}, __index = Accept}

function new(params)
	local obj = setmetatable({name=params.name or '',react=params.react,cb=params.cb,host=params.host,port=params.port,timeout=params.timeout,backlog=params.backlog or 200 ,logger=params.logger}, Accept_mt)
	local server = socket.bind(obj.host, obj.port,obj.backlog)
	--if obj.backlog then
	--	server:listen(backlog)
	--end
	server:settimeout(obj.timeout or 0)
	obj.fd=server
	obj.__ev_recv=obj.react:AddEventCB(obj.OnClose,obj,obj:GetFD(),obj.react.EV_READ,obj.AcceptCB)
	obj.logger:info(obj.name .. ' listen on ' .. obj.host .. ':' .. obj.port)
	return obj
end

function server(newfun,params)
	assert(newfun)
	local mon=params.mon
	if mon then
		mon:__remove_subnodes()
	end
	params.cb=function(fd)
		local hm
		if mon then
			hm=mon:__sure_child(tostring(fd:getfd()))
		end
		local np=setmetatable({mon=hm,fd=fd},{__index=params})
		local cli=newfun(np)
	end
	return zsvc.accept.new(params)
end

function Accept:GetFD()
	return self.fd
end
function Accept:AcceptCB(event)
	local client = self:GetFD():accept()
	if client then
		self.logger:info(self.name .. ' accept socket:'.. tostring(client))
		client:settimeout(0)
		local r,msg=pcall(self.cb,client)
		if not r then
			self.logger:error(self.name .. ' accept error ' .. tostring(msg))
			client:shutdown()
		end
	end
	return self.react.EV_READ,self.rd__timeout
end

function Accept:OnClose()
	self.logger:info('Accept close fd for ' .. (self.fd:getpeername() or ''))
	if self.fd then
		self.fd:close()
	end
	self.fd=nil
end
